魔法方法 repr Python 有一个内置的函数叫 repr,它能把一个对象用字符串的形式表达出来以便辨认,这就是“字符串表示形式”。repr 就是通过 __repr__
这个特殊方法来得到一个对象的字符串表示形式的。如果没有实现 _repr__
,当我们在控制台里打印一个向量的实例时,得到的字符串可能会是 Vecto r object at 0x10e100070>
1 2 3 4 5 6 7 class AAA : def __repr__ (self) : return "AAA" aaa = AAA() print(aaa) print(repr(aaa))
str __repr__
和__str__
区别在于,后者是在 str() 函数被使用,或是在用 print 函数打印一个对象的时候才被调用的,并且它返回的字符串对终端用户更友好。如果你只想实现这两个特殊方法中的一个,__repr__
是更好的选择,因为一个对象没有 __str__
函数,而 Python 又需要调用它的时候,解释器会用__repr__
作为替代
1 2 3 4 5 6 class AAA : def __repr__ (self) : return "这里写什么就返回什么" aaa = AAA() print(str(aaa))
bool bool(x) 的背后是调用 x.__bool__()
的结果;如果不存在__bool__
方法,那么 bool(x) 会尝试调用 x.__len__()
。若返回 0,则 bool 会返回 False;否则返回 True。
切片 元组拆包 1 2 3 4 5 print(divmod(20 , 8 )) t = (20 , 8 ) print(divmod(*t))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 a, b, *rest = range(5 ) print(f"a: {a} , b: {b} , rest: {rest} " ) a, b, *rest = range(3 ) print(f"a: {a} , b: {b} , rest: {rest} " ) a, b, *rest = range(2 ) print(f"a: {a} , b: {b} , rest: {rest} " ) a, *body, c, d = range(5 ) print(f"a: {a} , body: {body} , c: {c} , d:{d} " ) *head, b, c, d = range(5 ) print(f"head: {head} , b: {b} , c: {c} , d:{d} " )
嵌套元组拆包 1 2 3 4 5 6 7 8 9 users = [ ("张三" , "男" , "20" , ("湖北省" , "武汉市" , "xx区" )), ("李四" , "男" , "34" , ("江苏省" , "南京市" , "xx区" )) ] for name, sex, age, (province, city, area) in users: print(province, city, area)
具名元组 创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from collections import namedtupleusers = namedtuple("users" , "name sex age position" ) u1 = users("李四" , "男" , "34" , ("江苏省" , "南京市" , "xx区" )) print(u1.name, u1.sex, u1.age, u1.position) print(u1._fields) print(u1._asdict()) print(u1._replace(sex="女" )) print(u1.count("淮安" )) u2 = users._make(("张三" , "男" , "20" , ("湖北省" , "武汉市" , "xx区" ))) print(u2)
切片赋值 1 2 3 4 5 6 7 8 9 10 11 12 13 l = list(range(10 )) print(l) l[2 :5 ] = [20 , 30 ] print(l) del l[5 :7 ]print(l) l[3 ::2 ] = [11 , 22 ] print(l) l[2 :5 ] = 100
序列的增量赋值 增量赋值运算符 += 和 *= 后面的概念和理论都是一样的,这里以 += 进行举例。+= 背后的特殊方法是 __iadd__
(用于“就地加法”, 不会创建新对象,还是修改当前对象的值)。但是如果一个类没有实现这个方法的话,Python 会退一步调用 __add__
。考虑下面这个简单的表达式:
如果 a 实现了__iadd__
方法,就会调用这个方法。同时对可变序列(例如 list、bytearray 和 array.array)来说,a 会就地改动,就像调用了 a.extend(b) 一样。但是如果 a 没有实现 __iadd__
的话,a += b 这个表达式的效果就变得跟 a = a + b 一样了:首先计算 a +b,得到一个新的对象,然后赋值给 a。也就是说,在这个表达式中,变量名会不会被关联到新的对象,完全取决于这个类型有没有实现 __iadd__
这个方法。总体来讲,可变序列一般都实现了 __iadd__
方法,因此 += 是就地加法(不会创建新对象)。而不可变序列根本就不支持这个操作(会创建新对象)。上面所说的这些关于 += 的概念也适用于 *=,不同的是,后者相对应的是 __imul__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 l = [1 , 2 , 3 ] print(l) print(id(l)) l *= 2 print(l) print(id(l)) print("====================================" ) t = (1 , 2 , 3 ) print(t) print(id(t)) t *= 2 print(t) print(id(t))
一个关于+=的谜题 1 2 3 4 5 6 7 8 9 10 下面代码会发生下面 4 种情况中的哪一种? >>> t = (1, 2, [30, 40]) >>> t[2] += [50, 60] a. t 变成 (1, 2, [30, 40, 50, 60])。 b. 因为 tuple 不支持对它的元素赋值,所以会抛出 TypeError 异常。 c. 以上两个都不是。 d. a 和 b 都是对的。 答案:a,b。被改变成了 (1, 2, [30, 40, 50, 60]),但是也抛出了异常。如果改写成 t[2].extend([50, 60]) 就能避免这个异常。
list.sort 和 sorted list.sort 方法会就地排序列表,也就是说不会把原列表复制一份(不会创建新的内存空间,使用 id 查看到的内存地址是一致的)。这也是这个方法的返回值是 None 的原因,提醒你本方法不会新建一个列表。
在这种情况下返回 None 其实是 Python 的一个惯例:如果一个函数或者方法对对象进行的是就地改动,那它就应该返回 None,好让调用者知道传入的参数发生了变动,而且并未产生新的对象。用返回 None 来表示就地改动这个惯例有个弊端,那就是调用者无法将其串联起来。而返回一个新对象的方法(比如说 str 里的所有方法)则正好相反,它们可以串联起来调用,从而形成连贯接口。
与 list.sort 相反的是内置函数 sorted,它会新建一个列表作为返回值。这个方法可以接受任何形式的可迭代对象作为参数,甚至包括不可变序列或生成器。而不管 sorted 接受的是怎样的参数,它最后都会返回一个列表。不管是 list.sort 方法还是 sorted 函数,都有两个可选的关键字参数,reverse 和 key。
1 2 3 4 5 6 7 8 9 a = ["aa" , "ccc" , "ee" , "dddd" ] print(sorted(a)) print(sorted(a, reverse=True )) print(sorted(a, reverse=True , key=len))
因为排序算法是稳定的,aa和 ee的长度都是 2,所以它们的相对位置跟在原来的列表里是一样的。
bisect bisect 是 python 内置模块,用于有序序列的插入和查找
查找
1 2 3 4 5 import bisect a = [1 ,4 ,6 ,8 ,12 ,15 ,20 ] position = bisect.bisect(a,12 ) position_left = bisect.bisect_left(a,12 )
插入并排序
1 2 3 4 5 import bisect a = [1 ,4 ,6 ,8 ,12 ,15 ,20 ] bisect.insort(a,13 ) print(a)
综合实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import bisectHAYSTACK = [1 , 4 , 5 , 6 , 8 , 12 , 15 , 20 , 21 , 23 , 23 , 26 , 29 , 30 ] NEEDLES = [0 , 1 , 2 , 5 , 8 , 10 , 22 , 23 , 29 , 30 , 31 ] ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}' def demo (bisect_fn) : for needle in reversed(NEEDLES): position = bisect_fn(HAYSTACK, needle) offset = position * ' |' print(ROW_FMT.format(needle, position, offset)) if __name__ == '__main__' : bisect_fn = bisect.bisect print('DEMO:' , bisect_fn.__name__) print('haystack ->' , ' ' .join('%2d' % n for n in HAYSTACK)) demo(bisect_fn)
array https://www.cnblogs.com/jlf0103/p/9168093.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from array import arrayfrom random import randomfloats = array('d' , (random() for i in range(10 **7 ))) print(floats[-1 ]) fp = open('floats.bin' , 'wb' ) floats.tofile(fp) fp.close() floats2 = array('d' ) fp = open('floats.bin' , 'rb' ) floats2.fromfile(fp, 10 **7 ) fp.close() print(floats[-1 ] == floats2[-1 ])
deque collections.deque 类(双向队列)是一个线程安全、可以快速从两端添加或者删除元素的数据类型。而且如果想要有一种数据类型来存放“最近用到的几个元素”,deque 也是一个很好的选择。这是因为在新建一个双向队列的时候,你可以指定这个队列的大小,如果这个队列满员了,还可以从反向端删除过期的元素,然后在尾端添加新的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from collections import dequedq = deque(range(10 ), maxlen=10 ) print(dq) dq.rotate(3 ) print(dq) dq.rotate(-4 ) print(dq) dq.appendleft(-1 ) print(dq) dq.extend([10 , 11 , 12 ]) print(dq) dq.extendleft([-3 , -4 , -5 ]) print(dq)
字典找不到 key 时返回默认值 defaultdict
1 2 3 4 5 6 7 8 9 10 11 from collections import defaultdictdd = defaultdict(list) print(dd.get("zhangsan" )) print(dd["zhangsan" ])
__missing__
__missing__
方法只会被 __getitem__
调用(比如在表达式 d[k] 中)。提供 __missing__
方法对 get 或者__contains__
(in 运算符会用到这个方法)这些方法的使用没有影响。这也是我在上一节最后的警告中提到,defaultdict 中的default_factory 只对 __getitem__
有作用的原因。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class StrKeyDict0 (dict) : """ StrKeyDict0 继承了 dict 如果找不到的键本身就是字符串,那就抛出 KeyError 异常 如果找不到的键不是字符串,那么把它转换成字符串再进行查找 isinstance(key, str) 测试在上面的__missing__ 中是必需的。如果没有这个测试,只要 str(k) 返回的是一个存在的键,那么__missing__ 方法是没问题的,不管是字符串键还是非字符串键,它都能正常运行。但是如果 str(k) 不是一个存在的键,代码就会陷入无限递归。这是因为 __missing__ 的最后一行中的 self[str(key)] 会调用 __getitem__,而这个 str(key) 又不存在,于是 __missing__又会被调用。 同样在 __contains__ 方法中,也不能使用 key in my_dict 来检查 key 是否存在,因为那也会导致 __contains__ 被递归调用 """ def __missing__ (self, key) : if isinstance(key, str): raise KeyError(key) return self[str(key)] def get (self, key, default=None) : try : return self[key] except KeyError: return default def __contains__ (self, key) : return key in self.keys() or str(key) in self.keys()
OrderedDict 这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的。OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素,但是如果像 my_odict.popitem(last=False) 这样调用它,那么它删除并返回第一个被添加进去的元素。
1 2 3 4 5 6 7 8 9 10 11 from collections import OrderedDictnew_dict = OrderedDict() new_dict["a" ] = "a" new_dict["c" ] = "c" new_dict["d" ] = "d" new_dict["b" ] = "b" print(new_dict) print(new_dict.popitem()) print(new_dict.popitem(last=False ))
ChainMap https://www.cnblogs.com/mangmangbiluo/p/9882097.html
该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止。这个功能在给有嵌套作用域的语言做解释器的时候很有用,可以用一个映射对象来代表一个作用域的上下文。
不可变字典 标准库里所有的映射类型都是可变的,从 Python 3.3 开始,types 模块中引入了一个封装类名叫MappingProxyType。如果给这个类一个映射,它会返回一个只读的映射视图。虽然是个只读视图,但是它是动态的。这意味着如果对原映射做出了改动,我们通过这个视图可以观察到,但是无法通过这个视图对原映射做出修改。
1 2 3 4 5 6 7 8 from types import MappingProxyTyped = {"a" : "a" , "b" : "b" , "c" :"c" } proxy_d = MappingProxyType(d) print(proxy_d) print(proxy_d["a" ]) proxy_d["a" ] = 1
字典中的散列表 散列表其实是一个稀疏数组(总是有空白元素的数组称为稀疏数组)。在一般的数据结构教材中,散列表里的单元通常叫作表元(bucket)。在 dict 的散列表当中,每个键值对都占用一个表元,每个表元都有两个部分,一个是对键的引用,另一个是对值的引用。因为所有表元的大小一致,所以可以通过偏移量来读取某个表元。Python 会设法保证大概还有三分之一的表元是空的,所以在快要达到这个阈值的时候,原有的散列表会被复制到一个更大的空间里面。如果要把一个对象放入散列表,那么首先要计算这个元素键的散列值。Python 中可以用 hash() 方法来做这件事情。从 Python 3.3 开始,str、bytes 和 datetime 对象的散列值计算过程中多了随机的“加盐”这一步。所加盐值是 Python 进程内的一个常量,但是每次启动 Python 解释器都会生成一个不同的盐值。随机盐值的加入是为了防止 DOS 攻击而采取的一种安全措施。
为了获取 my_dict[search_key] 背后的值,Python 首先会调用 hash(search_key) 来计算 search_key 的散列值,把这个值最低的几位数字当作偏移量,在散列表里查找表元(具体取几位,得看当前散列表的大小)。若找到的表元是空的,则抛出 KeyError 异常。若不是空的,则表元里会有一对 found_key:found_value。这时候 Python 会检验 search_key == found_key 是否为真,如果它们相等的话,就会返回 found_value。如果 search_key 和found_key 不匹配的话,这种情况称为散列冲突。发生这种情况是因为,散列表所做的其实是把随机的元素映 射到只有几位的数字上,而散列表本身的索引又只依赖于这个数字的一部分。为了解决散列冲突,算法会在散列值中另外再取几位,然后用特殊的方法处理一下,把新得到的数字再当作索引来寻找表元。若这次找到的表元是空的,则同样抛出 KeyError;若非空,或者键匹配,则返回这个值;或者又发现了散列冲突,则重复以上的步骤。
添加新元素和更新现有键值的操作几乎跟上面一样。只不过对于前者,在发现空表元的时候会放入一个新元素;对于后者,在找到相对应的表元后,原表里的值对象会被替换成新值。另外在插入新值时,Python 可能会按照散列表的拥挤程度来决定是否要重新分配内存为它扩容。如果增加了散列表的大小,那散列值所占的位数和用作索引的位数都会随之增加,这样做的目的是为了减少发生散列冲突的概率。
字典键的次序取决于添加顺序 当往 dict 里添加新键而又发生散列冲突的时候,新键可能会被安排存放到另一个位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 DIAL_CODES = [ (86 , 'China' ), (91 , 'India' ), (1 , 'United States' ), (62 , 'Indonesia' ), (55 , 'Brazil' ), (92 , 'Pakistan' ), (880 , 'Bangladesh' ), (234 , 'Nigeria' ), (7 , 'Russia' ), (81 , 'Japan' ), ] d1 = dict(DIAL_CODES) print('d1:' , d1.keys()) print('d1:' , d1) d2 = dict(sorted(DIAL_CODES)) print('d2:' , d2.keys()) print('d2:' , d2) d3 = dict(sorted(DIAL_CODES, key=lambda x:x[1 ])) print('d3:' , d3.keys()) print('d3:' , d3) assert d1 == d2 and d2 == d3
无论何时往字典里添加新的键,Python 解释器都可能做出为字典扩容的决定。扩容导致的结果就是要新建一个更大的散列表,并把字典里已有的元素添加到新表里。这个过程中可能会发生新的散列冲突,导致新散列表中键的次序变化。
保留最后 N 个元素 1 2 3 4 5 6 7 8 9 10 11 12 13 from collections import dequeq = deque(maxlen=3 ) q.append(1 ) q.append(2 ) q.append(3 ) q.append(4 ) print(q) print(q.pop()) print(q.popleft())
查找最大或最小的 N 个元素 1 2 3 4 5 6 7 8 import heapqnums = [1 , 8 , 2 , 23 , 7 , -4 , 18 , 23 , 42 , 37 , 2 ] print(heapq.nlargest(3 , nums)) print(heapq.nsmallest(3 , nums))
按照某些规则获取查找最大或最小的 N 个元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 portfolio = [ {'name' : 'IBM' , 'shares' : 100 , 'price' : 91.1 }, {'name' : 'AAPL' , 'shares' : 50 , 'price' : 543.22 }, {'name' : 'FB' , 'shares' : 200 , 'price' : 21.09 }, {'name' : 'HPQ' , 'shares' : 35 , 'price' : 31.75 }, {'name' : 'YHOO' , 'shares' : 45 , 'price' : 16.35 }, {'name' : 'ACME' , 'shares' : 75 , 'price' : 115.65 } ] import heapqprint(heapq.nlargest(3 , portfolio, key=lambda x:x["price" ])) print(heapq.nsmallest(3 , portfolio, key=lambda x:x["price" ]))
将元素排序后,每次返回最小的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 import heapqnums = [1 , 8 , 2 , 23 , 7 , -4 , 18 , 23 , 42 , 37 , 2 ] heapq.heapify(nums) print(heapq.heappop(nums)) print(heapq.heappop(nums)) print(heapq.heappop(nums)) print(heapq.heappop(nums)) print(heapq.heappop(nums)) print(heapq.heappop(nums))
实现一个优先级队列 1 2 3 4 5 6 7 8 9 10 11 import heapqnums = [(1 , 1 ), (-1 , 3 ),(-1 , 2 ), (1 , 0 )] heapq.heapify(nums) print(heapq.heappop(nums)) print(heapq.heappop(nums)) print(heapq.heappop(nums)) print(heapq.heappop(nums))
根据 heapq 的排序原理(按照元素第一个值排序,第一个值相同在按照第二个),heappop 每次返回一个最小的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import heapqclass PriorityQueue : def __init__ (self) : self._queue = [] self._index = 0 def push (self, item, priority) : heapq.heappush(self._queue, (-priority, self._index, item)) self._index += 1 def pop (self) : return heapq.heappop(self._queue)[-1 ] class Item : def __init__ (self, name) : self.name = name def __repr__ (self) : return 'Item({!r})' .format(self.name) q = PriorityQueue() q.push(Item('foo' ), 1 ) q.push(Item('bar' ), 5 ) q.push(Item('spam' ), 4 ) q.push(Item('grok' ), 1 ) print(q.pop()) print(q.pop()) print(q.pop()) print(q.pop())
由于 push 和 pop 操作时间复杂度为 O(log N),其中 N 是堆的大小,因此就算是 N 很大的时候它们运行速度也依旧很快。 在上面代码中,队列包含了一个 (-priority, index, item)
的元组。 优先级为负数的目的是使得元素按照优先级从高到低排序。 这个跟普通的按优先级从低到高排序的堆排序恰巧相反。index
变量的作用是保证同等优先级元素的正确排序。 通过保存一个不断增加的 index
下标变量,可以确保元素按照它们插入的顺序排序。 而且, index
变量也在相同优先级元素比较的时候起到重要作用。
字典中的键映射多个值 普通实现
1 2 3 4 5 6 7 8 9 10 11 d = { 'a' : [1 , 2 , 3 ], 'b' : [4 , 5 ] } e = { 'a' : {3 , 1 , 2 , 3 , 3 }, 'b' : {4 , 5 , 4 } }
defaultdict 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from collections import defaultdictd = defaultdict(list) d["a" ].append(1 ) d["a" ].append(2 ) d["a" ].append(4 ) d["a" ].append(5 ) print(d) s = defaultdict(set) s["a" ].add(1 ) s["a" ].add(2 ) s["a" ].add(4 ) s["a" ].add(4 ) print(s)
setdefault 实现
1 2 3 4 5 c = {} c.setdefault('a' , []).append(1 ) c.setdefault('a' , []).append(2 ) c.setdefault('b' , []).append(4 ) print(c)
有序字典 1 2 3 4 5 6 7 8 9 from collections import OrderedDictd = OrderedDict() d['foo' ] = 1 d['bar' ] = 2 d['spam' ] = 3 d['grok' ] = 4 print(d)
OrderedDict
内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候, 它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会改变键的顺序。需要注意的是,一个 OrderedDict
的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。
查找两字典的相同点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 a = { 'x' : 1 , 'y' : 2 , 'z' : 3 } b = { 'w' : 10 , 'x' : 11 , 'y' : 2 } print(a.keys() & b.keys()) print(a.keys() - b.keys()) print(a.items() & b.items())
删除序列相同元素并保持顺序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def dedupe (items, key=None) : seen = set() for item in items: val = item if key is None else key(item) if val not in seen: yield item seen.add(val) a = [ {'x' :1 , 'y' :2 }, {'x' :1 , 'y' :3 }, {'x' :1 , 'y' :2 }, {'x' :2 , 'y' :4 }] print(list(dedupe(a, key=lambda d: (d['x' ],d['y' ])))) b = [1 , 5 , 2 , 1 , 9 , 1 , 5 , 10 ] print(list(dedupe(b)))
slice 1 2 3 4 5 items = [0 , 1 , 2 , 3 , 4 , 5 , 6 ] name_slice = slice(2 , 4 ) print(items[name_slice]) print(items[2 :4 ])
序列中出现次数最多的元素 1 2 3 4 5 6 7 8 9 10 11 12 13 words = [ 'look' , 'into' , 'my' , 'eyes' , 'look' , 'into' , 'my' , 'eyes' , 'the' , 'eyes' , 'the' , 'eyes' , 'the' , 'eyes' , 'not' , 'around' , 'the' , 'eyes' , "don't" , 'look' , 'around' , 'the' , 'eyes' , 'look' , 'into' , 'my' , 'eyes' , "you're" , 'under' ] from collections import Counterword_counts = Counter(words) print(word_counts.most_common(3 ))
通过某个关键字排序一个字典列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 rows = [ {'fname' : 'Brian' , 'lname' : 'Jones' , 'uid' : 1003 }, {'fname' : 'David' , 'lname' : 'Beazley' , 'uid' : 1002 }, {'fname' : 'John' , 'lname' : 'Cleese' , 'uid' : 1001 }, {'fname' : 'Big' , 'lname' : 'Jones' , 'uid' : 1004 } ] from operator import itemgetterrows_by_fname = sorted(rows, key=itemgetter("fname" )) print(rows_by_fname) rows_by_lfname = sorted(rows, key=itemgetter("fname" , "lname" )) print(rows_by_lfname) rows_by_fname2 = sorted(rows, key=lambda r: r['fname' ]) rows_by_lfname2 = sorted(rows, key=lambda r: (r['lname' ],r['fname' ]))
itemgetter 同样也适用于 max,min
排序不支持比较的对象 可以借助对象的属性的值来进行排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class User : def __init__ (self, user_id) : self.user_id = user_id def __repr__ (self) : return 'User({})' .format(self.user_id) users = [User(23 ), User(3 ), User(99 )] print(sorted(users, key=lambda x:x.user_id)) from operator import attrgetterprint(sorted(users, key=attrgetter("user_id" )))
attrgetter同样也适用于 max,min
通过某个字段将记录分组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 rows = [ {'address' : '5412 N CLARK' , 'date' : '07/01/2012' }, {'address' : '5148 N CLARK' , 'date' : '07/02/2012' }, {'address' : '5800 E 58TH' , 'date' : '07/02/2012' }, {'address' : '2122 N CLARK' , 'date' : '07/03/2012' }, {'address' : '5645 N RAVENSWOOD' , 'date' : '07/02/2012' }, {'address' : '1060 W ADDISON' , 'date' : '07/02/2012' }, {'address' : '4801 N BROADWAY' , 'date' : '07/01/2012' }, {'address' : '1039 W GRANVILLE' , 'date' : '07/03/2012' }, ] from itertools import groupbyfrom operator import itemgetterrows.sort(key=itemgetter('date' )) for k, v in groupby(rows, key=itemgetter("date" )): print(k) for x in v: print(" " , x) """ 07/01/2012 {'address': '5412 N CLARK', 'date': '07/01/2012'} {'address': '4801 N BROADWAY', 'date': '07/01/2012'} 07/02/2012 {'address': '5148 N CLARK', 'date': '07/02/2012'} {'address': '5800 E 58TH', 'date': '07/02/2012'} {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'} {'address': '1060 W ADDISON', 'date': '07/02/2012'} 07/03/2012 {'address': '2122 N CLARK', 'date': '07/03/2012'} {'address': '1039 W GRANVILLE', 'date': '07/03/2012'} """
将相同日期的数据放到同一个 list 当中
1 2 3 4 5 6 from collections import defaultdictrows_by_date = defaultdict(list) for row in rows: rows_by_date[row['date' ]].append(row) print(rows_by_date)
过滤序列元素 列表推导式
1 2 3 4 mylist = [1 , 4 , -5 , 10 , -7 , 2 , 3 , -1 ] print([x for x in mylist if x < 0 ])
生成器
1 2 3 4 a = (x for x in mylist if x < 0 ) print(list(a))
Filter
1 2 3 4 5 def less (x) : return True if x < 0 else False print(list(filter(less, mylist)))
compress
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from itertools import compressaddresses = [ '5412 N CLARK' , '5148 N CLARK' , '5800 E 58TH' , '2122 N CLARK' , '5645 N RAVENSWOOD' , '1060 W ADDISON' , '4801 N BROADWAY' , '1039 W GRANVILLE' , ] selector = [True , True , False , False , True ] print(list(compress(addresses, selector)))
命名元组 1 2 3 4 5 6 7 8 9 10 11 12 13 from collections import namedtupleUser = namedtuple("User" , ["name" , "age" ]) u1 = User("zhangsan" , 20 ) u2 = User("lisi" , 30 ) print(u1, u2) u11 = u1._replace(name="wanghwu" ) print(u11)